'''
> 注: 这整篇实验介绍就是一个python程序, 你可以直接复制粘贴到一个.py文件中并运行(需要pip install physicsLab)
> <discussion=642cf37a494746375aae306a>关于physicsLab</discussion>

float32_t是c++23新增的定宽浮点数, 也就是32位浮点数
((flaot32_t)[https://zh.cppreference.com/w/cpp/types/floating_point])
这个实验也是一个**完全遵守**IEEE-754中32位浮点数的表示方法的浮点加法
目测该实验应该是物实首例

## 如何操作该实验
有2列逻辑输入(每列共32个), 你需要分别输入2个遵循IEEE-754标准的浮点数
1列有32个元件的逻辑输出, 是输出结果
左下角的逻辑输入为时钟, 需要用户手动提供输入的时钟
左下角还有个逻辑输出, 当这个逻辑输出始终为1的时候, 表示计算完成
***在左下角逻辑输出始终为1之前的任何输出都是无效的***

> 为什么让用户手动提供时钟? 当然不是偷懒()。而是因为这种电路的时钟应该由电脑主板上的一个总的tick来提供(比如晶振)
> 没有制作重置按钮, 这确实是偷懒()。因此本实验只能运算一次

## IEEE-754标准中的32位浮点数
1.  符号位(s), s为1时表示负数, 共1位
2.  指数位(exp), 共8位
3.  小数位(frac), 共23位

浮点数的表示思路为科学计数法, 也就是 (-1)^s * (2^指数) * 小数
注意, 我这里没有使用exp与frac进行表示, 是因为exp与frac需要进行一定的转换后才是上式的指数与小数
下面是转换规则的介绍

exp与frac分为规格化与非规格化两种表示方式(下面关于exp与frac的公式仅限于32位浮点数)
* 当exp == 0时, 为非规格化的值
* 当exp != 0时, 为规格化的值
非规格化的值: 指数 = -126, 小数没有默认的1
规格化的值: 指数 = exp - 127, 小数会有一个默认的1
(感觉讲得不是很清楚的亚子, 自己读CSAPP去())
(而且这些表示方式只是一种设计而已, 太过于执着于去问为什么并不是很好。)
(实际上在我实际实现这个电路的时候也感觉一些设计让实现不是那么方便)

当exp == 255且frac的23位全为0时, 表示无穷, 结合符号位可表示正无穷与负无穷
当exp == 255且frac的23位不全为0时, 表示NaN, 此时符号位无意义

## 测试用例
* NaN +或- xxx = NaN
* 正无穷 + 正无穷 = 正无穷
* 正无穷 + 负无穷 = NaN
* 负无穷 + 正无穷 = 负无穷
* 0.75 + 1
* 0.1 + 0.2
* 0.1 - 0.2
* 0.2 - 0.1
* 2.93874e-39 + 4.4081e-39
* 2.93874e-39 - 4.4081e-39
* 8.81621e-39 + 4.4081e-39
* 8.81621e-39 - 4.4081e-39
* 2.05712e-38 + 4.4081e-39

上述测试用例的输出结果与 https://godbolt.org/z/dhne6f8nj 上测试得到的结果一致
测试用例涵盖的情况还是很广, 也因此折磨了我一周来做这个电路
但如有你遇到了bug欢迎提出, 虽然也不一定修掉()

下面是源代码:
'''

from os import path
from physicsLab import *

def is_NaN(x: numType, y: numType, z: numType, _input: lib.Inputs):
    orgates = lib.Super_OrGate(x, y, z, bitnum=23)
    for i, o in zip(_input.frac, orgates.inputs):
        i.o - o

    andgates = lib.Super_AndGate(x, y + 12, z, bitnum=8)
    for i, o in zip(_input.exp, andgates.inputs):
        i.o - o

    res = And_Gate(x, y + 15, z)
    res.i_low - orgates.output
    res.i_up - andgates.output

    norgate = Nor_Gate(x, y - 1, z) # 判断无穷需要的元件, 与NaN无关
    orgates.output.element_self.i_low - norgate.i_low
    orgates.output.element_self.i_up - norgate.i_up
    return res.o

def is_infinite(x: numType, y: numType, z: numType, _input: lib.Inputs):
    andgate = And_Gate(x, y, z)
    andgate.i_up - get_Element(x, 12, 0)[-1].o
    andgate.i_low - get_Element(x, -1, 0).o
    return andgate.o

with experiment("float32_t运算电路计划", extra_filepath="float32_t") as expe:
    set_elementXYZ(True)
    set_O(-1, -1, 0)

    start_button = Logic_Input(-1, 0, 0)
    start_button.set_Rotation(0, 0, -90)
    input1 = lib.Inputs(0, 0, 0, bitnum=32, heading=False)
    input2 = lib.Inputs(1, 0, 0, bitnum=32, heading=False)
    output = lib.Outputs(2, 0, 0, bitnum=32, heading=False)
    input1.frac = input1[0:23]
    input1.exp = input1[23:31]
    input1.s = input1[31]
    for input1_element in input1.exp:
        input1_element.set_Rotation(0, 0, 0)
    input2.frac = input2[0:23]
    input2.exp = input2[23:31]
    input2.s = input2[31]
    for input2_element in input2.exp:
        input2_element.set_Rotation(0, 0, 0)
    for output_element in output[23:31]:
        output_element.set_Rotation(0, 0, 0)

    end_compute = Logic_Output(-1.5, 0, 0).set_Rotation(0, 0, -90)
    end_compute_orgate = lib.Super_OrGate(-1, -2, -1, bitnum=4)
    end_compute_orgate.output - end_compute.i

    infinete_output_orgate = Or_Gate(3, 0, 0)
    infinete_output_orgate.o - output.inputs[0]
    output_orgate = lib.MultiElements(3, 23, 0, bitnum=9, element=Or_Gate)
    output_orgate.pins(output_orgate[0].o) - output.inputs[23:32]
    exp_orgates2 = []
    for _y in range(8):
        _orgate = Or_Gate(3, 23 + _y, 1)
        _orgate.o - output_orgate[_y].i_up
        exp_orgates2.append(_orgate)

    input1_is_NaN = is_NaN(4, 0, 0, input1)
    input2_is_NaN = is_NaN(5, 0, 0, input2)
    _is_NaN_orgate = Or_Gate(4, 17, 0)
    _is_NaN_orgate.i_low - input1_is_NaN
    _is_NaN_orgate.i_up - input2_is_NaN
    _is_NaN_orgate.o - end_compute_orgate.inputs[0]
    NaN_orgate = Or_Gate(5, 17, 0)
    _is_NaN_orgate.o - NaN_orgate.i_low
    infinete_output_orgate.i_low - NaN_orgate.o
    for pin in output_orgate.pins(output_orgate[0].i_low)[:8]:
        NaN_orgate.o - pin

    input1_is_infinete = is_infinite(4, 20, 0, input1)
    input2_is_infinete = is_infinite(5, 20, 0, input2)
    infinete_NaN = lib.Super_AndGate(4, 21, 0, bitnum=3) # 正无穷与负无穷相加为NaN
    infinete_NaN_s = Xor_Gate(4, 23, 0)
    infinete_NaN_s.i_low - input1.s.o
    infinete_NaN_s.i_up - input2.s.o
    infinete_NaN.inputs[0] - input1_is_infinete
    infinete_NaN.inputs[1] - input2_is_infinete
    infinete_NaN.inputs[2] - infinete_NaN_s.o
    infinete_NaN.output - NaN_orgate.i_up
    any_is_infinete = Or_Gate(5, 21, 0)
    any_is_infinete.i_low - input1_is_infinete
    any_is_infinete.i_up - input2_is_infinete
    for _orgate in exp_orgates2:
        any_is_infinete.o - _orgate.i_low
    # 无穷的符号的处理电路
    infinete_s_andgate = And_Gate(5, 22, 0)
    infinete_s_andgate.i_low - any_is_infinete.o
    infinete_s_orgate = Or_Gate(5, 23, 0)
    input1_s_andgate = And_Gate(4, 24, 0)
    input1_s_andgate.i_up - input1.s.o
    input1_s_andgate.i_low - input1_is_infinete
    input2_s_andgate = And_Gate(5, 24, 0)
    input2_s_andgate.i_up - input2.s.o
    input2_s_andgate.i_low - input2_is_infinete
    infinete_s_orgate.i_low - input1_s_andgate.o
    infinete_s_orgate.i_up - input2_s_andgate.o
    infinete_s_andgate.i_up - infinete_s_orgate.o
    infinete_s_andgate.o - output_orgate[-1].i_low
    any_is_infinete.o - end_compute_orgate.inputs[1]

    # 一般情况的运算电路
    in_case_not_input = Nimp_Gate(0, -1, 0)
    in_case_not_input_ = lib.Rising_edge_trigger(0, -3, 0)
    start_button.o - in_case_not_input_.i
    in_case_not_input_.o - in_case_not_input.i_up
    in_case_not_input.i_low - end_compute_orgate.output

    input1_frac_register = lib.Switched_Register(6, -2, 0, bitnum=25) # 1 + 23 + 1, 因为IEEE754中隐藏的1
    input2_frac_register = lib.Switched_Register(8, -2, 0, bitnum=25) # 而且右移额外保留一位数字
    for i, intpu1_exp in enumerate(input1.frac):
        intpu1_exp.o - input1_frac_register.inputs1[i + 1]
    for i, intput2_exp in enumerate(input2.frac):
        intput2_exp.o - input2_frac_register.inputs1[i + 1]
    switch_forever = Or_Gate(1, -1, 0)
    switch_forever.i_low - switch_forever.o
    switch_forever.i_up - in_case_not_input.o
    switch_forever.o - input1_frac_register.switch
    switch_forever.o - input2_frac_register.switch

    input1_exp_register = lib.Switched_Register(6, 20, 1, bitnum=8)
    input2_exp_register = lib.Switched_Register(8, 20, 1, bitnum=8)
    for i, intpu1_exp in enumerate(input1.exp):
        if i == 0:
            continue
        intpu1_exp.o - input1_exp_register.inputs1[i]
    for i, intput2_exp in enumerate(input2.exp):
        if i == 0:
            continue
        intput2_exp.o - input2_exp_register.inputs1[i]
    input1_exp_register_clk = Multiplier(6, 20, 2)
    input1_exp_register_clk.i_up - input1_exp_register.switch.element_self.o
    input1_exp_register_clk.i_lowmid - input1_exp_register.switch.element_self.i
    input1_exp_register_clk.o_lowmid - input1_exp_register.clk
    input2_exp_register_clk = Multiplier(8, 20, 2)
    input2_exp_register_clk.i_up - input2_exp_register.switch.element_self.o
    input2_exp_register_clk.i_lowmid - input2_exp_register.switch.element_self.i
    input2_exp_register_clk.o_lowmid - input2_exp_register.clk
    in_case_not_input.o - input1_exp_register_clk.i_low
    in_case_not_input.o - input2_exp_register_clk.i_low
    switch_forever.o - input1_exp_register.switch
    switch_forever.o - input2_exp_register.switch

    input1_exp_is_not_zero = lib.Super_OrGate(4, 12, 1, bitnum=8)
    for i, input1_exp in enumerate(input1.exp):
        input1_exp_is_not_zero.inputs[i] - input1_exp.o
    input2_exp_is_not_zero = lib.Super_OrGate(5, 12, 1, bitnum=8)
    for i, input2_exp in enumerate(input2.exp):
        input2_exp_is_not_zero.inputs[i] - input2_exp.o
    input1_exp_is_not_zero.output - input1_frac_register.inputs1[-1]
    input2_exp_is_not_zero.output - input2_frac_register.inputs1[-1]

    # 如果是非规格化浮点数(exp == 0)则exp=1
    input1_exp_if_zero = Imp_Gate(4, 21, 1)
    input2_exp_if_zero = Imp_Gate(5, 21, 1)
    input1_exp_if_zero.o - input1_exp_register.inputs1[0]
    input2_exp_if_zero.o - input2_exp_register.inputs1[0]
    input1_exp_is_not_zero.output - input1_exp_if_zero.i_up
    input2_exp_is_not_zero.output - input2_exp_if_zero.i_up
    input1.exp[0].o - input1_exp_if_zero.i_low
    input2.exp[0].o - input2_exp_if_zero.i_low

    # 对input1.exp与input2.exp进行大小比较
    is_equal_to = lib.Equal_to(10, 20, 1, bitnum=8)
    is_equal_to.inputs1 - input1_exp_register.outputs
    is_equal_to.inputs2 - input2_exp_register.outputs
    # ==> input1.exp - input2.exp
    input1_than_input2 = lib.Sub(11, 20, 1, bitnum=8)
    input1_than_input2.minuend - input1_exp_register.outputs
    input1_than_input2.subtrahend - input2_exp_register.outputs
    is_less_than = No_Gate(13, 34, 1)
    is_less_than.i - input1_than_input2.outputs[-1]
    is_more_than = Nimp_Gate(13, 35, 1)
    is_more_than.i_up - input1_than_input2.outputs[-1]
    is_more_than.i_low - is_equal_to.output

    is_less_than_andgate = And_Gate(6, 22, 2)
    is_more_than_andgate = And_Gate(8, 22, 2)
    in_case_not_input.o - is_less_than_andgate.i_low
    in_case_not_input.o - is_more_than_andgate.i_low
    is_less_than_andgate.i_up - is_less_than.o
    is_more_than_andgate.i_up - is_more_than.o
    is_less_than_andgate.o - input1_exp_register_clk.i_upmid
    is_more_than_andgate.o - input2_exp_register_clk.i_upmid

    # exp_register加1电路(为frac_register右移的一部分运算电路)
    const_nogate = lib.Const_NoGate(14, 19, 1)
    input1_exp_sub = lib.Sum(14, 20, 1, bitnum=8)
    input1_exp_register.outputs - input1_exp_sub.inputs1
    input1_exp_sub.outputs[:8] - input1_exp_register.inputs2
    const_nogate.o - input1_exp_sub.inputs2[0]
    input2_exp_sub = lib.Sum(15, 20, 1, bitnum=8)
    input2_exp_register.outputs - input2_exp_sub.inputs1
    input2_exp_sub.outputs[:8] - input2_exp_register.inputs2
    const_nogate.o - input2_exp_sub.inputs2[0]

    # # 查看exp_register的值
    # print_input1_exp = lib.Outputs(12, 0, 3, bitnum=8)
    # print_input2_exp = lib.Outputs(13, 0, 3, bitnum=8)
    # print_input1_exp.inputs - input1_exp_register.outputs
    # print_input2_exp.inputs - input2_exp_register.outputs

    # frac_register右移电路
    input1_frac_register_clk = Multiplier(6, 0, 1)
    input1_frac_register_clk.i_up - input1_frac_register.switch.element_self.o
    input1_frac_register_clk.i_lowmid - input1_frac_register.switch.element_self.i
    input1_frac_register_clk.i_upmid - is_less_than_andgate.o
    input1_frac_register_clk.i_low - in_case_not_input.o
    input1_frac_register_clk.o_lowmid - input1_frac_register.clk
    input2_frac_register_clk = Multiplier(8, 0, 1)
    input2_frac_register_clk.i_up - input2_frac_register.switch.element_self.o
    input2_frac_register_clk.i_lowmid - input2_frac_register.switch.element_self.i
    input2_frac_register_clk.i_upmid - is_more_than_andgate.o
    input2_frac_register_clk.i_low - in_case_not_input.o
    input2_frac_register_clk.o_lowmid - input2_frac_register.clk
    for i in range(1, 25):
        input1_frac_register.outputs[i] - input1_frac_register.inputs2[i - 1]
        input2_frac_register.outputs[i] - input2_frac_register.inputs2[i - 1]

    # # 查看frac_register的值
    # print_input1_frac = lib.Outputs(16, 0, 2, bitnum=25)
    # print_input2_frac = lib.Outputs(17, 0, 2, bitnum=25)
    # print_input1_frac.inputs - input1_frac_register.outputs
    # print_input2_frac.inputs - input2_frac_register.outputs

    inputs_signed_sum = lib.Signed_Sum(10, -2, 0, bitnum=26) # 25 + 1，处理加法溢出
    inputs_signed_sum.inputs1[:-1] - input1_frac_register.outputs
    inputs_signed_sum.inputs2[:-1] - input2_frac_register.outputs
    inputs_signed_sum.inputs1_sign - input1.s.o
    inputs_signed_sum.inputs2_sign - input2.s.o
    inputs_signed_sum.outputs_sign - output_orgate[-1].i_up

    # 浮点对阶与加法完成后的格式化并输出
    output_format_frac_register = lib.Switched_Register(14, -2, 0, bitnum=26)
    output_format_frac_register.inputs1 - inputs_signed_sum.outputs
    for i in range(0, output_format_frac_register.bitnum - 1):
        output_format_frac_register.inputs2[i + 1] - output_format_frac_register.outputs[i]
    when_to_switch_andgate = lib.Super_AndGate(14, 0, 1, bitnum=3)
    when_to_switch_andgate.inputs[0] - is_equal_to.output
    when_to_switch_andgate.inputs[1] - in_case_not_input.o
    when_to_switch_andgate.inputs[2] - switch_forever.o
    # when_to_switch_andgate.output - output_format_frac_register.clk
    when_to_switch = Or_Gate(14, -1, 1)
    when_to_switch.i_up - when_to_switch_andgate.output
    when_to_switch.i_low - when_to_switch.o
    when_to_switch.o - output_format_frac_register.switch
    # 将exp+1使电路能处理溢出
    plusplus_exp = lib.Sum(16, 21, 1, bitnum=8)
    plusplus_exp.inputs1 - input1_exp_register.outputs
    plusplus_exp.inputs2[0] - const_nogate.o
    # 浮点对阶处理exp的电路
    output_format_exp_register = lib.Switched_Register(17, 21, 1, bitnum=8)
    plusplus_exp.outputs[:8] - output_format_exp_register.inputs1
    output_format_exp_register.clk - when_to_switch_andgate.output
    when_to_switch.o - output_format_exp_register.switch
    output_format_exp_register_sub = lib.Sum(19, 21, 1, bitnum=8)
    output_format_exp_register.outputs - output_format_exp_register_sub.inputs1
    output_format_exp_register_sub.outputs[:8] - output_format_exp_register.inputs2
    for pin in output_format_exp_register_sub.inputs2:
        pin - const_nogate.o

    # 处理frac输出值的舍入
    output_format_frac = lib.Sum(16, 2, 0, bitnum=24)
    output_format_frac.inputs1 - output_format_frac_register.outputs[2:]
    # 向偶数舍入
    e0 = Or_Gate(16, 1, 0)
    e1 = Nimp_Gate(16, 0, 0)
    e2 = And_Gate(16, -1, 0)
    e3 = And_Gate(16, -2, 0)
    e1.i_up - output_format_frac_register.outputs[1]
    e1.i_low - output_format_frac_register.outputs[0]
    e2.i_up - output_format_frac_register.outputs[2]
    e2.i_low - e1.o
    e3.i_up - output_format_frac_register.outputs[1]
    e3.i_low - output_format_frac_register.outputs[0]
    e0.i_low - e3.o
    e0.i_up - e2.o
    output_format_frac.inputs2[0] - e0.o
    # 如果exp是255, 则输出无穷大(frac为0)
    output_exp_is_255 = lib.Super_AndGate(20, 21, 1, bitnum=8)
    output_format_exp_register.outputs - output_exp_is_255.inputs
    no_output_if_infinete = lib.MultiElements(17, 0, 0, bitnum=24, element=Nimp_Gate)
    for pin in no_output_if_infinete.pins(no_output_if_infinete[0].i_low):
        pin - output_exp_is_255.output
    no_output_if_infinete.pins(no_output_if_infinete[0].i_up) - output_format_frac.outputs[:-1]
    # exp如果是0则直接输出非规格化的浮点数
    output_exp_is_0_ = lib.Super_OrGate(20, 23, 1, bitnum=7)
    output_exp_is_0_.inputs - output_format_exp_register.outputs[1:]
    output_exp_is_0 = Nor_Gate(21, 23, 1)
    output_exp_is_0.i_up - output_exp_is_0_.output
    output_exp_is_0.i_low - output_format_exp_register.outputs[0]
    output_exp_is_0_andgate = And_Gate(20, 27, 1)
    output_exp_is_0_andgate.i_up - output_exp_is_0.o
    output_exp_is_0_andgate.i_low - when_to_switch.o
    end_compute_orgate.inputs[3] - output_exp_is_0_andgate.o
    # exp如果是1就不移位了, 因为exp为非规格化浮点数时没有省略的1位
    output_exp_is_1 = Nimp_Gate(21, 24, 1)
    output_exp_is_1.i_up - output_format_exp_register.outputs[0]
    output_exp_is_1.i_low - output_exp_is_0_.output
    no_clk_when_exp_is_1 = Nimp_Gate(15, -3, 0)
    when_to_switch_andgate.output - no_clk_when_exp_is_1.i_up
    no_clk_when_exp_is_1.i_low - output_exp_is_1.o
    no_clk_when_exp_is_1.o - output_format_frac_register.clk
    # 输出frac的值
    no_output_if_infinete.pins(no_output_if_infinete[0].o)[0] - infinete_output_orgate.i_up
    no_output_if_infinete.pins(no_output_if_infinete[0].o)[1:23] - output.inputs[1:23]
    output_format_frac_register.outputs[-1] - end_compute_orgate.inputs[2]
    # 输出exp的值
    for i, orgate in enumerate(exp_orgates2):
        orgate.i_up - output_format_exp_register.outputs[i]


    with open(path.abspath(__file__), encoding="utf-8") as f:
        expe.edit_publish_info(
            introduction=f.read()
        )
